import java.util.HashMap;
import java.util.LinkedList;



public class AIPlayer extends Player{
	private GameState g;	
	private HandEvaluator handEval;
	private HandCompTest handCompT;
	private LinkedList<Action> oppActionLog;
	private HashMap<Player, Integer> oppStrength;
	private HashMap<Player, Integer> oppHandStrength;
	private double myHandStrength;
	private boolean beWary;
	public AIPlayer(GameState gState)
	{
		super("Default AI name");
		g = gState;
		this.type = "AI";
		handEval = new HandEvaluator();
		handCompT = new HandCompTest();
		oppStrength = new HashMap<Player,Integer>();
		oppHandStrength = new HashMap<Player,Integer>();		
		beWary = false;
	}
	public AIPlayer(String n, GameState gState)
	{
		super(n);
		this.type = "AI";
		g = gState;
		oppStrength = new HashMap<Player,Integer>();
		oppHandStrength = new HashMap<Player,Integer>();
		handEval = new HandEvaluator();
		handCompT = new HandCompTest();
	}
	public String act(String[] validActions, int lastCurrBet)
	{
		System.out.println("" + this.getName() + " is thinking...");
		oppActionLog = g.getActionLog();
		updateOppInfo();
		myHandStrength = calcHandStrength();
		g.clearActionLog();
		hasActed=true;
		return decide(validActions, lastCurrBet);
	}
	public void init()
	{
		LinkedList<Player> temp = g.getPlayers();
		for(int i=0; i<temp.size(); i++)
		{
			oppStrength.put(temp.get(i), 0);
			oppHandStrength.put(temp.get(i), 0);
		}
	}
	private void updateOppInfo()
	{
		if(oppActionLog.size() != 0)
		{
			for(int i=0; i<oppActionLog.size(); i++)
			{
				Action oppAction = oppActionLog.get(i);
				int prevStrength = oppHandStrength.get(oppAction.getPlayer());
				if(oppAction.getAction().equals("bet"))
				{				
					oppHandStrength.put(oppAction.getPlayer(), prevStrength+ (oppAction.getAmount()/10));
				}
				else if(oppActionLog.get(i).equals("raise"))
				{				
					oppHandStrength.put(oppAction.getPlayer(), prevStrength+ (oppAction.getAmount()/5));
				}
				else if(oppActionLog.get(i).equals("call"))
				{
					oppHandStrength.put(oppAction.getPlayer(), prevStrength+ (oppAction.getAmount()/12));
				}
				else if(oppActionLog.get(i).equals("check"))
				{
					oppHandStrength.put(oppAction.getPlayer(), prevStrength - (oppAction.getAmount()/20));
				}
				else
				{
					oppHandStrength.put(oppAction.getPlayer(), 0);
				}
			}
		}
	}
	public void resetRound()
	{
		LinkedList<Player> temp = g.getPlayers();
		for(int i=0; i<temp.size(); i++)
		{
			oppHandStrength.put(temp.get(i), 0);
		}
	}
	private String decide(String[] validActions, int lastCurrBet)
	{
		if(validActions[0] == "bet")
		{
			boolean toBet = false;
			if(myHandStrength*2/g.getNumPlayers() > 50.0*2/g.getNumPlayers())
			{
				toBet = true;
				if(shouldBeWary())
				{
					calcBet(1);					
				}
				else
				{
					calcBet(0);
				}
			}
			if(toBet)
				return "bet";
			else
				return "check";
		}
		else
		{
			boolean toRaise = false;
			boolean toCall = false;
			if(myHandStrength*2/g.getNumPlayers() > 70.0*2/g.getNumPlayers())
			{
				toRaise = true;
				if(shouldBeWary())
				{
					calcBet(1);					
				}
				else
				{
					calcBet(0);
				}
			}
			else if(myHandStrength*2/g.getNumPlayers() > 50.0*2/g.getNumPlayers())
			{
				toCall = true;				
			}
			if(toRaise && !hasRaised)
			{
				hasRaised = true;
				return "raise";
			}
			else if(toRaise && hasRaised)
			{
				return "call";
			}
			else if(toCall)
			{
				setBet(lastCurrBet);
				return "call";
			}
			else
				return "fold";
		}
	}
	public void playerWon(Player p)
	{
		int prevVal = oppStrength.get(p);
		oppStrength.put(p, (int)(prevVal+(Math.random()*5)));
	}
	private void calcBet(int mode) //0 for normal, 1 for wary, 2 for slowplay
	{
		if(mode == 0)
		{
			if(g.getPot() == 0)
			{
				if(myHandStrength > 50.0)
				{
					this.setBet((int)(10*(myHandStrength-50)));
				}
			}
			else
			{
				if(myHandStrength > 50.0)
				{
					this.setBet((int)(10*(myHandStrength-50)));
				}
			}
		}
	}
	private boolean shouldBeWary()
	{
		return beWary;
	}
	private void checkWary()
	{
		LinkedList<Player> p = g.getPlayers();
		for(int i=0; i<p.size();i++)
		{
			if(oppHandStrength.get(p.get(i)) > 50)
			{
				beWary = true;
			}
		}
	}
	private double calcHandStrength()
	{
		if(g.getCurrRound() == 0)
		{
			return handEval.preFlopHandRank(this.getHoleCards());
		}
		else{
			/// load an array with the community cards and players (2) cards
			int sizeOfCommCardz = g.getCommCards().size();
			Card[] cardz = new Card[sizeOfCommCardz + 2];
			int i=0;
			// loading community cards
			for(i = 0; i < sizeOfCommCardz; i++){
				cardz[i] = g.getCommCards().get(i);
			}
			// loading players two cards
			cardz[i] = this.getHoleCards().get(0);
			i++;
			cardz[i] = this.getHoleCards().get(1);
			
			/// pass it to the handcomptester
			double rvalue = handCompT.handComp(cardz);
			rvalue = ((rvalue /2099)* 100 );
			return rvalue;
		}	
	}
	public void printOppInfo()
	{
		System.out.println();
		System.out.println("--- " + this.getName() + " ---");
		System.out.println("Perceived Player Strength");
		LinkedList<Player> temp = g.getPlayers();
		for(int i=0; i<oppStrength.size(); i++)
		{
			System.out.println("     " + temp.get(i).getName() + " - " + oppStrength.get(temp.get(i)));
		}
		
	}
}
